package com.lcache.core.test;

import com.alibaba.fastjson.JSONObject;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.websocketx.*;
import lombok.extern.slf4j.Slf4j;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

import static org.reflections.Reflections.log;

@Slf4j
public class LocalWebSocketClient {
    private static final String WS_URL = "ws://localhost:8091/ws";
    private Channel channel;
    private EventLoopGroup group;
    private WebSocketClientHandler handler;
    private final CountDownLatch handshakeLatch = new CountDownLatch(1);

    public boolean connect() throws Exception {
        group = new NioEventLoopGroup();
        try {
            handler = new WebSocketClientHandler(
                    WebSocketClientHandshakerFactory.newHandshaker(
                            new URI(WS_URL), WebSocketVersion.V13, null, false, null),
                    handshakeLatch);

            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws URISyntaxException {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(new HttpClientCodec());
                            pipeline.addLast(new HttpObjectAggregator(65536));
                            pipeline.addLast(new WebSocketClientProtocolHandler(
                                    new URI(WS_URL), WebSocketVersion.V13, null, false, null, 65536));
                            pipeline.addLast(handler);
                        }
                    });

            channel = bootstrap.connect("localhost", 8091).sync().channel();
            // 等待握手完成
            if (!handshakeLatch.await(5, TimeUnit.SECONDS)) {
                LocalWebSocketClient.log.error("WebSocket handshake timeout");
                return false;
            }
            System.out.println("Connected to WebSocket server at {}" + WS_URL);
            return true;
        } catch (Exception e) {
            LocalWebSocketClient.log.error("Connect to WebSocket server failed", e);
            group.shutdownGracefully();
            throw e;
        }
    }

    public void send(String message) {
        if (channel == null || !channel.isActive()) {
            throw new IllegalStateException("WebSocket is not connected");
        }
        channel.writeAndFlush(new TextWebSocketFrame(message));
        System.out.println("Sent message: {}"+ message);
    }

    public void close() {
        try {
            if (channel != null && channel.isActive()) {
                channel.writeAndFlush(new CloseWebSocketFrame()).sync();
                channel.closeFuture().sync();
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            if (group != null) {
                group.shutdownGracefully();
            }
            System.out.println("Disconnected from WebSocket server");
        }
    }

    public static void main(String[] args) {
        LocalWebSocketClient client = new LocalWebSocketClient();
        try {
            // 1. 连接到服务器
            if (!client.connect()) {
                return;
            }

            // 2. 构造并发送登录消息
            JSONObject loginMsg = new JSONObject();
            loginMsg.put("type", "login");
            loginMsg.put("userId", "user_123");
            loginMsg.put("username", "user_123");
            loginMsg.put("password", "password123");
            client.send(loginMsg.toJSONString());

            // 3. 等待1秒
            TimeUnit.SECONDS.sleep(1);

            // 4. 构造并发送聊天消息
            JSONObject chatMsg = new JSONObject();
            chatMsg.put("type", "single");
            chatMsg.put("userId", "user_123");
            chatMsg.put("toUserId", "user_456");
            chatMsg.put("message", "跨服务 hello,456");
            client.send(chatMsg.toJSONString());

            // 5. 等待1秒
            TimeUnit.SECONDS.sleep(1);
        } catch (Exception e) {
            LocalWebSocketClient.log.error("Client error", e);
        } finally {
            client.close();
        }
    }
}

class WebSocketClientHandler extends SimpleChannelInboundHandler<WebSocketFrame> {
    private final CountDownLatch handshakeLatch;

    public WebSocketClientHandler(WebSocketClientHandshaker handshaker,
                                  CountDownLatch handshakeLatch) {
        this.handshakeLatch = handshakeLatch;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) {
        if (frame instanceof TextWebSocketFrame) {
            String text = ((TextWebSocketFrame) frame).text();
            System.out.println("Received message: " + text);
        }
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
        if (evt == WebSocketClientProtocolHandler.ClientHandshakeStateEvent.HANDSHAKE_COMPLETE) {
            handshakeLatch.countDown();
            System.out.println("WebSocket handshake completed");
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.error("WebSocket error", cause);
        ctx.close();
    }
}